﻿using Newtonsoft.Json;
using NLog;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;

namespace WWDemon.Log
{
    /// <summary>
    ///     程序日志包装类,提供统一的Log操作入口111.
    ///     包含静态构造函数,用于初始化,可能抛出异常.
    ///     任何工程使用,都必须在进程启动时候,打出进程启动日志,以保证日志正常启动.
    /// </summary>
    public static class LogHelper
    {
        public delegate void LogEvel(LogLevel logDefinition, string msg);

        /// <summary>
        ///     写日志
        /// </summary>
        public static event LogEvel OnLogEvel;

        #region < 变量 >

        //日志记录器,用于记录系统日志
        //private static readonly ILog _Log;

        #endregion < 变量 >

        #region < 静态构造 >

        /// <summary>
        ///     静态构造函数,可能抛出异常
        /// </summary>
        [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
        [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
        private static readonly Logger m_Logger;

        static LogHelper()
        {
            m_Logger = LogManager.GetCurrentClassLogger();
        }

        private static string Key = string.Empty;

        public static void Init(string key)
        {
            Key = key;
        }

        #endregion < 静态构造 >

        #region < 日志记录方法,系统日志 >

        /// <summary>
        ///     记录日志
        /// </summary>
        /// <param name="logDefinition">日志类型及消息定义</param>
        /// <param name="exception">异常对象(如果有异常)</param>
        /// <param name="args">格式化输出的实际参数</param>
        public static void Log(LogDefinition logDefinition, object msg)
        {
            try
            {
                LogCore(logDefinition.LogLevel, logDefinition.LogDesc, null, msg, null, true);
            }
            catch
            {
            }
        }

        /// <summary>
        ///     记录日志
        /// </summary>
        /// <param name="logDefinition">日志类型及消息定义</param>
        /// <param name="exception">异常对象(如果有异常)</param>
        /// <param name="args">格式化输出的实际参数</param>
        public static void Log(LogDefinition logDefinition, Exception exception, object msg)
        {
            try
            {
                LogCore(logDefinition.LogLevel, logDefinition.LogDesc, exception, msg, null, true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("异常:" + exception.Message + ", 写日志异常:" + ex.Message);
            }
        }

        /// <summary>
        ///     记录日志
        /// </summary>
        /// <param name="logDefinition">日志类型及消息定义</param>
        /// <param name="args">格式化输出的实际参数</param>
        public static void Log(LogDefinition logDefinition, object msg, object data)
        {
            try
            {
                LogCore(logDefinition.LogLevel, logDefinition.LogDesc, null, msg, data, true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("写日志异常:" + ex.Message + "," + ex.StackTrace);
            }
        }

        /// <summary>
        ///     记录日志
        /// </summary>
        /// <param name="logDefinition">日志类型及消息定义</param>
        /// <param name="args">格式化输出的实际参数</param>
        public static void LogNotEvel(LogDefinition logDefinition, object msg, object data)
        {
            try
            {
                LogCore(logDefinition.LogLevel, logDefinition.LogDesc, null, msg, data, false);
            }
            catch (Exception ex)
            {
                Console.WriteLine("写日志异常:" + ex.Message + "," + ex.StackTrace);
            }
        }

        /// <summary>
        ///     记录日志
        /// </summary>
        /// <param name="logDefinition">日志类型及消息定义</param>
        /// <param name="exception">异常对象(如果有异常)</param>
        /// <param name="args">格式化输出的实际参数</param>
        public static void Log(LogDefinition logDefinition, Exception exception, object msg, object data)
        {
            try
            {
                LogCore(logDefinition.LogLevel, logDefinition.LogDesc, exception, msg, data, true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("异常:" + exception.Message + ", 写日志异常:" + ex.Message);
            }
        }

        /// <summary>
        ///     记录日志,为了堆栈统一,提供私有方法
        /// </summary>
        /// <param name="logLevel">日志级别</param>
        /// <param name="message">日志信息</param>
        /// <param name="exception">异常对象(如果有异常)</param>
        /// <param name="args">格式化输出的实际参数</param>
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        private static void LogCore(LogLevel logLevel, string message, Exception exception, object msg, object data, bool evel)
        {
            //先判断是否需要记录,如果不需记录则直接返回,不再进行后续处理

            //进行日志消息格式化处理,并对非基本对象进行并行序列化处理
            string dataString = string.Empty;
            try
            {
                //如果提供了待格式化串和参数则进行格式化处理

                if (data != null)
                {
                    var type = data.GetType();
                    if (!type.IsPrimitive && type.IsClass && type.Name != "String")
                        dataString = JsonConvert.SerializeObject(data);
                    else
                    {
                        dataString = data.ToString();
                    }
                }
                message = string.Format(CultureInfo.InvariantCulture, message, msg);
            }
            catch (Exception ex)
            {
                m_Logger.Fatal(ex, string.Format(CultureInfo.InvariantCulture, "日志信息格式化错误, Message:{0}", message));
            }

            var nowTime = DateTime.Now;
            //根据日志级别写入对应日志
            switch (logLevel)
            {
                case LogLevel.Info:

                    Console.ForegroundColor = ConsoleColor.Gray;
                    Console.WriteLine($"{nowTime}  {message} ,{dataString}");
                    m_Logger.Info(exception, Key + " " + message + "," + dataString);
                    break;

                case LogLevel.Warn:
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine($"{nowTime}  {message} ,{dataString}");
                    m_Logger.Warn(exception, Key + " " + message + "," + dataString);
                    break;

                case LogLevel.Error:
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"{nowTime}  {message} ,{dataString} {exception?.StackTrace}");
                    m_Logger.Error(exception, Key + " " + message + "," + dataString);
                    break;

                case LogLevel.Fatal:
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine($"{nowTime}  {message}");
                    m_Logger.Fatal(exception, Key + " " + message + "," + dataString);
                    break;

                case LogLevel.Debug:
                    Console.ForegroundColor = ConsoleColor.Blue;
                    Console.WriteLine($"{nowTime}  {message} ,{dataString}");
                    m_Logger.Debug(exception, Key + " " + message + "," + dataString);
                    break;

                case LogLevel.Verbose:
                    Console.ForegroundColor = ConsoleColor.Blue;
                    Console.WriteLine($"{nowTime}  {message},{dataString}");
                    m_Logger.Debug(exception, Key + " " + message + "," + dataString);
                    break;
            }

            if (evel)
            {
                OnLogEvel?.Invoke(logLevel, message);
            }
        }

        #endregion < 日志记录方法,系统日志 >
    }
}